home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue64 / Alfresco / AAHpClss.pas next >
Encoding:
Pascal/Delphi Source File  |  2000-10-23  |  6.3 KB  |  222 lines

  1. {*********************************************************}
  2. {* AAHpClss                                              *}
  3. {* Copyright (c) Julian M Bucknall 2000                  *}
  4. {* All rights reserved.                                  *}
  5. {*********************************************************}
  6. {* Algorithms Alfresco: Object creation analyzer         *}
  7. {*********************************************************}
  8.  
  9. {Note: this unit is released as freeware. In other words, you are free
  10.        to use this unit in your own applications, however I retain all
  11.        copyright to the code. JMB}
  12.  
  13. unit AAHpClss;
  14.  
  15. {Notes: This unit should be put first in the project's uses list, or,
  16.         if SHAREMEM is being used, second (ie, just under ShareMem).
  17.         In other words you should have this uses list in your
  18.         project's DPR file:
  19.  
  20.           uses
  21.             HeapClss,
  22.             ..other units..
  23.  
  24.         or, this one:
  25.  
  26.           uses
  27.             ShareMem,
  28.             HeapClss,
  29.             ..other units..
  30.  
  31.         The code in the unit tracks every object creation and free
  32.         providing that NewInstance and FreeInstance have not been
  33.         overridden and the ancestor's version called. It produces a
  34.         log file called C:\AAClass.LOG.
  35.  
  36.         The log file consists of a line per allocation or free in the
  37.         follwing format:
  38.  
  39.           <TYPE> <ADDRESS> <CLASS NAME>
  40.  
  41.         where <TYPE> is 'New:' or 'Free:', <ADDRESS> is the address of
  42.         the just created object or the object about to be freed, and
  43.         <CLASS NAME> is the name of the class for the object in
  44.         question. Here's an example, extracted from an actual log:
  45.  
  46.           Free: 00bc598c TList
  47.           New:  00bc6e10 TList
  48.           Free: 00bc6e10 TList
  49.           New:  00bc6e10 TObject
  50.           Free: 00bc6e10 TObject
  51.           Free: 00bc560c TFont
  52.  
  53.         If you want to alter this code to add more functionality,
  54.         notice that you cannot cause any memory allocations to occur
  55.         in the GetMem replacement routine, otherwise you will blow the
  56.         stack pretty quickly.}
  57.  
  58. interface
  59.  
  60. implementation
  61.  
  62. var
  63.   Log : System.Text;
  64.  
  65.   OrigHeap : TMemoryManager;
  66.   OurHeap  : TMemoryManager;
  67.  
  68.   NewInstAddr  : longint;
  69.   FreeInstAddr : longint;
  70.   CreateAddr   : longint;
  71.  
  72. type
  73.   PNewInstCallStack = ^TNewInstCallStack;
  74.   TNewInstCallStack = record
  75.     csOldEBP        : longint;
  76.     csGetMemRetAddr : longint; // actually a pointer
  77.     csNewInstRetAddr: longint; // actually a pointer
  78.     csClassInstance : TClass;
  79.   end;
  80.  
  81.   PFreeInstCallStack = ^TFreeInstCallStack;
  82.   TFreeInstCallStack = record
  83.     csOldEBP         : longint;
  84.     csFreeMemRetAddr : longint; //pointer;
  85.     csFreeInstRetAddr: longint; //pointer;
  86.   end;
  87.  
  88. {===Helper routines==================================================}
  89. function ByteAsHex(Dest : PChar; B : byte) : PChar;
  90. const
  91.   HexChars : array [0..15] of char = '0123456789abcdef';
  92. begin
  93.   if (Dest <> nil) then begin
  94.     Dest[0] := HexChars[B shr 4];
  95.     Dest[1] := HexChars[B and $F];
  96.     Dest[2] := #0;
  97.   end;
  98.   Result := Dest;
  99. end;
  100. {--------}
  101. function PointerAsHex(Dest : PChar; P : pointer) : PChar;
  102. var
  103.   L : longint;
  104. begin
  105.   if (Dest <> nil) then begin
  106.     L := longint(P);
  107.     ByteAsHex(Dest, L shr 24);
  108.     inc(Dest, 2);
  109.     ByteAsHex(Dest, (L shr 16) and $FF);
  110.     inc(Dest, 2);
  111.     ByteAsHex(Dest, (L shr 8) and $FF);
  112.     inc(Dest, 2);
  113.     ByteAsHex(Dest, L and $FF);
  114.   end;
  115.   Result := Dest;
  116. end;
  117. {====================================================================}
  118.  
  119.  
  120. {===Replacement memory routines======================================}
  121. function OurGetMem(Size: Integer): Pointer;
  122. var
  123.   CallStack : PNewInstCallStack;
  124.   PtrString : array [0..8] of char;
  125. begin
  126.   {get the call stack}
  127.   asm
  128.     mov CallStack, ebp
  129.   end;
  130.  
  131.   {allocate the memory}
  132.   Result := OrigHeap.GetMem(Size);
  133.  
  134.   {if this was called from TObject.NewInstance, output a line to the
  135.    log showing the object details}
  136.   if (NewInstAddr <= CallStack^.csNewInstRetAddr) and
  137.      (CallStack^.csNewInstRetAddr < FreeInstAddr) then begin
  138.     PointerAsHex(PtrString, Result);
  139.     writeln(Log, 'New:  ', PtrString, ' ',
  140.             Size:10, ' ',     
  141.             CallStack^.csClassInstance.ClassName);
  142.   end;
  143. end;
  144. {--------}
  145. function OurFreeMem(P : Pointer) : integer;
  146. type
  147.   PClass = ^TClass;
  148. var
  149.   CallStack : PFreeInstCallStack;
  150.   ClassPtr  : PClass;
  151.   PtrString : array [0..8] of char;
  152. begin
  153.   {get the call stack}
  154.   asm
  155.     mov CallStack, ebp
  156.   end;
  157.  
  158.   {if this was called from TObject.FreeInstance, output a line to the
  159.    log showing the object details. Note this only works because the
  160.    first field of the object being freed is the class pointer}
  161.   if (FreeInstAddr <= CallStack^.csFreeInstRetAddr) and
  162.      (CallStack^.csFreeInstRetAddr < CreateAddr) then begin
  163.     PointerAsHex(PtrString, P);
  164.     ClassPtr := P;
  165.     writeln(Log, 'Free: ', PtrString, ' ',
  166.             ' ':10, ' ',
  167.             ClassPtr^.ClassName);
  168.   end;
  169.  
  170.   {free the memory}
  171.   Result := OrigHeap.FreeMem(P);
  172. end;
  173. {====================================================================}
  174.  
  175.  
  176. {===Initialization/finalization======================================}
  177. procedure InitializeUnit;
  178. begin
  179.   {get the addresses of NewInstance, FreeInstance and Create as
  180.    integers}
  181.   NewInstAddr := longint(@TObject.NewInstance);
  182.   FreeInstAddr := longint(@TObject.FreeInstance);
  183.   CreateAddr := longint(@TObject.Create);
  184.  
  185.   {open up the log file}
  186.   System.Assign(Log, 'C:\AAClass.LOG');
  187.   System.Rewrite(Log);
  188.   writeln(Log, 'Algorithms Alfresco Object Creation/Destruction Log');
  189.   writeln(Log);
  190.   writeln(Log, 'Type   Address       Size Class');
  191.  
  192.   {get the original manager}
  193.   GetMemoryManager(OrigHeap);
  194.  
  195.   {set up our heap manager}
  196.   OurHeap.GetMem := OurGetMem;
  197.   OurHeap.FreeMem := OurFreeMem;
  198.   OurHeap.ReallocMem := OrigHeap.ReallocMem;
  199.  
  200.   {replace heap manager with ours}
  201.   SetMemoryManager(OurHeap);
  202. end;
  203. {--------}
  204. procedure FinalizeUnit;
  205. begin
  206.   {restore the original manager}
  207.   SetMemoryManager(OrigHeap);
  208.  
  209.   {close the log}
  210.   writeln(Log, '..finished..');
  211.   System.Close(Log);
  212. end;
  213. {====================================================================}
  214.  
  215. initialization
  216.   InitializeUnit;
  217.  
  218. finalization
  219.   FinalizeUnit;
  220.  
  221. end.
  222.